﻿using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

public abstract class MetadataLabeledObjectSymbol : MetadataSymbol
{
    private DomainSymbolTable? _categorySymbols;

    private MetadataArealSymbolTable? _labelStyleSymbols;

    // 元数据成员符号
    private MetadataArealSymbolTable? _propertySymbols;
    private MetadataArealSymbolTable? _styleSymbols;
    private DomainSymbolTable? _suffixSymbols;
    private MetadataArealSymbolTable? _templateSymbols;

    internal MetadataLabeledObjectSymbol(SymbolKinds kind, MetadataFieldSymbol? containingField,
        MetadataLabeledObject declaration) : base(kind, declaration)
    {
        ContainingSymbol = containingField;
    }


    public override ISymbol? ContainingSymbol { get; }

    internal DomainSymbolTable? CategoriesNullable => _categorySymbols;


    private DomainSymbolTable GetDomainSymbolTable(ref DomainSymbolTable? field)
    {
        return field ??= new DomainSymbolTable(this);
    }


    private MetadataArealSymbolTable GetMetadataArealSymbolTable(ref MetadataArealSymbolTable? field)
    {
        return field ??= new MetadataArealSymbolTable(this);
    }


    internal DomainSymbolTable GetCategorySymbols()
    {
        return GetDomainSymbolTable(ref _categorySymbols);
    }


    internal DomainSymbolTable GetSuffixSymbols()
    {
        return GetDomainSymbolTable(ref _suffixSymbols);
    }


    internal MetadataArealSymbolTable GetPropertySymbols()
    {
        return GetMetadataArealSymbolTable(ref _propertySymbols);
    }


    internal MetadataArealSymbolTable GetTemplateSymbols()
    {
        return GetMetadataArealSymbolTable(ref _templateSymbols);
    }


    internal MetadataArealSymbolTable GetStyleSymbols()
    {
        return GetMetadataArealSymbolTable(ref _styleSymbols);
    }


    internal MetadataArealSymbolTable GetLabelStyleSymbols()
    {
        return GetMetadataArealSymbolTable(ref _labelStyleSymbols);
    }


    public MetadataArealSymbol? FindProperty(string name, string context, string language, string labelType)
    {
        return _propertySymbols?.LookupSymbol(name, context, language, labelType) as MetadataArealSymbol;
    }


    public MetadataArealSymbol? FindTemplate(string name, string context, string language, string labelType)
    {
        return _templateSymbols?.LookupSymbol(name, context, language, labelType) as MetadataArealSymbol;
    }


    public MetadataArealSymbol? FindStyle(string name, string context, string language, string labelType)
    {
        return _styleSymbols?.LookupSymbol(name, context, language, labelType) as MetadataArealSymbol;
    }


    public MetadataArealSymbol? FindLabelStyle(string name, string context, string language, string labelType)
    {
        return _labelStyleSymbols?.LookupSymbol(name, context, language, labelType) as MetadataArealSymbol;
    }


    /// <summary>
    ///     声明一个后缀属性符号。
    /// </summary>
    public void DeclareSuffix(MetadataSuffixSymbol symbol)
    {
        if (_suffixSymbols?.TryGetSymbol(symbol.Name, out ISymbol? exist) == true)
        {
            ((MetadataSuffixSymbol)exist).Redeclare(symbol);
            foreach (SyntaxLocation loc in symbol.GetLocations())
            {
                exist.Reference(loc);
            }
        }
        else
        {
            GetSuffixSymbols().DeclareSymbol(symbol);
        }
    }


    public override bool Redeclare(ISymbol symbol)
    {
        if (symbol is not MetadataLabeledObjectSymbol labeledSymbol)
        {
            return false;
        }

        // 添加引用列表
        foreach (SyntaxLocation loc in labeledSymbol.GetLocations())
        {
            Reference(loc);
        }

        // 合并属性列表
        labeledSymbol._propertySymbols?.ForEach(s => GetPropertySymbols().DeclareSymbol(s));
        // 合并模板列表
        labeledSymbol._templateSymbols?.ForEach(s => GetTemplateSymbols().DeclareSymbol(s));
        // 合并样式列表
        labeledSymbol._styleSymbols?.ForEach(s => GetStyleSymbols().DeclareSymbol(s));
        // 合并标签样式列表
        labeledSymbol._labelStyleSymbols?.ForEach(s => GetLabelStyleSymbols().DeclareSymbol(s));
        // 合并后缀表
        labeledSymbol._suffixSymbols?.ForEach(s => GetSuffixSymbols().DeclareSymbol(s));

        return true;
    }
}